import tkinter as tk  # tkinter是Python内置的GUI库,用于创建图形用户界面
from tkinter import filedialog  # filedialog是tkinter中的一个模块,用于显示文件对话框
from tkinter import messagebox  # messagebox是tkinter中的一个模块,用于显示消息框
from PIL import Image, ImageTk  # PIL是Python的图像处理库,用于加载、操作和保存图像
import os  # os模块提供了与操作系统交互的功能,如文件路径操作
import numpy as np  # numpy是Python的数值计算库,用于处理数组和矩阵
import image_channels  # image_channels是一个自定义模块,用于分割和合并图像通道
import image_io  # image_io是一个自定义模块,用于加载和保存图像
import image_transform  # image_transform是一个自定义模块,用于图像变换
import config  # config是一个自定义模块,用于存储应用程序的配置信息
import sys  # sys模块提供了与Python解释器和运行环境相关的变量和函数
from image_utils import language_data, logging  # 从image_utils模块中导入language_data和logging
import image_utils as utils  # 导入image_utils模块并给它一个别名utils
import subprocess  # subprocess模块允许你生成新的进程，连接它们的输入、输出和错误管道，并获取它们的返回码
import cv2  # 添加OpenCV库的导入

class ImageProcessor:
    def __init__(self, master):
        """初始化ImageProcessor类的实例"""
        self.master = master  # 主窗口
        # 确保 language_data 中有 'current_language' 键
        self.current_language = language_data.get("current_language", "en")  # 默认语言通过JSON文件直接设置
        master.title(language_data[self.current_language]['app_title'])  # 设置初始窗口标题

        self.image = None  # 用于存储当前图像的numpy数组
        self.image_path = ""  # 用于存储当前图像的文件路径
        self.rect_start_x = None  # 用于存储裁剪矩形框起始点的x坐标
        self.rect_start_y = None  # 用于存储裁剪矩形框起始点的y坐标
        self.rect_end_x = None  # 用于存储裁剪矩形框结束点的x坐标
        self.rect_end_y = None  # 用于存储裁剪矩形框结束点的y坐标
        self.is_drawing = False  # 用于标记是否正在绘制裁剪矩形框
        self.current_rect = None  # 用于存储当前绘制的裁剪矩形框对象
        self.threshold = 128  # 初始阈值
        self.original_image = None  # 用于保存原图，便于阈值调整时恢复
        self.shift_value = 0  # 用于存储移动差分的偏移值
        self.current_mask = None  # 新增：用于存储当前生成的掩模
        
        self.create_widgets()  # 创建GUI组件

    def create_widgets(self):
        """创建GUI组件"""
        # 创建菜单栏
        menubar = tk.Menu(self.master)
        self.master.config(menu=menubar)

        # 创建文件菜单
        file_menu = tk.Menu(menubar)
        file_menu.add_command(label=language_data[self.current_language]['open_original'], command=self.Open_as_original)
        file_menu.add_command(label=language_data[self.current_language]['open_grayscale'], command=self.Open_as_gray)
        file_menu.add_command(label=language_data[self.current_language]['merge_channels'], command=self.merge_channels)
        file_menu.add_command(label=language_data[self.current_language]['save_image'], command=self.save_image)
        file_menu.add_separator()

        # 创建一个菜单项,用于切换语言,它应该有两个子菜单项,分别用于切换中文和英文。当前语言用一个勾选标记来表示。
        language_menu = tk.Menu(file_menu)
        self.language_var = tk.StringVar(value=self.current_language)
        language_menu.add_radiobutton(label="中文", variable=self.language_var, value="zh", command=self.change_language)
        language_menu.add_radiobutton(label="English", variable=self.language_var, value="en", command=self.change_language)
        file_menu.add_cascade(label=language_data[self.current_language]['language'], menu=language_menu)

        file_menu.add_command(label=language_data[self.current_language]['exit'], command=self.master.quit)
        menubar.add_cascade(label=language_data[self.current_language]['file'], menu=file_menu)

        # 创建信息菜单
        info_menu = tk.Menu(menubar)
        info_menu.add_command(label=language_data[self.current_language]['details'], command=self.show_image_details)
        menubar.add_cascade(label=language_data[self.current_language]['info'], menu=info_menu)

        # 创建编辑菜单
        edit_menu = tk.Menu(menubar)
        edit_menu.add_command(label=language_data[self.current_language]['crop'], command=self.crop_image)
        edit_menu.add_command(label=language_data[self.current_language]['reset'], command=self.reset_image)
        # 添加亮度调节选项
        edit_menu.add_command(label=language_data[self.current_language]['brightness_adjust'], command=self.adjust_brightness)
        menubar.add_cascade(label=language_data[self.current_language]['edit'], menu=edit_menu)

        # 创建图像分割菜单
        split_menu = tk.Menu(menubar)
        menubar.add_cascade(label=language_data[self.current_language]['split'], menu=split_menu)
        split_menu.add_command(label=language_data[self.current_language]['split_channels'], command=self.split_image_channels)

        # 创建阈值处理菜单
        threshold_menu = tk.Menu(menubar)
        menubar.add_cascade(label=language_data[self.current_language]['threshold_processing'], menu=threshold_menu)
        threshold_menu.add_command(label=language_data[self.current_language]['global_threshold'], command=self.global_threshold_processing)

       # 创建边缘菜单
        edge_menu = tk.Menu(menubar)
        menubar.add_cascade(label=language_data[self.current_language]['edge'], menu=edge_menu)
        edge_menu.add_command(label=language_data[self.current_language]['moving_difference'], command=self.moving_difference)

      # 创建掩膜菜单
        mask_menu = tk.Menu(menubar)
        menubar.add_cascade(label=language_data[self.current_language]['create_mask'], menu=mask_menu)
        mask_menu.add_command(label=language_data[self.current_language]['red_mask'], command=lambda: self.generate_mask('red'))
        mask_menu.add_command(label=language_data[self.current_language]['green_mask'], command=lambda: self.generate_mask('green'))
        mask_menu.add_command(label=language_data[self.current_language]['blue_mask'], command=lambda: self.generate_mask('blue'))

      # 创建位运算菜单
        bitwise_menu = tk.Menu(menubar)
        menubar.add_cascade(label=language_data[self.current_language]['bitwise_operations'], menu=bitwise_menu)
        bitwise_menu.add_command(label=language_data[self.current_language]['and_operation'], command=lambda: self.apply_mask('and'))
        bitwise_menu.add_command(label=language_data[self.current_language]['or_operation'], command=lambda: self.apply_mask('or'))
        bitwise_menu.add_command(label=language_data[self.current_language]['xor_operation'], command=lambda: self.apply_mask('xor'))
        bitwise_menu.add_command(label=language_data[self.current_language]['not_operation_invert'], command=self.invert_color)

        # 创建图像显示区域
        self.canvas = tk.Canvas(self.master, width=600, height=400)
        self.canvas.pack()

        self.canvas.bind("<Button-1>", self.on_mouse_down)
        self.canvas.bind("<B1-Motion>", self.on_mouse_move)
        self.canvas.bind("<ButtonRelease-1>", self.on_mouse_up)

    def invert_color(self):
        """实现图像反色功能"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['no_image_loaded'])
            return

        # 保存原始图像以便重置
        if self.original_image is None:
            self.original_image = self.image.copy()

        # 执行反色操作
        self.image = cv2.bitwise_not(self.image)
        
        # 显示处理后的图像
        self.display_image()
        
        logging.info("Image color inverted")
        tk.messagebox.showinfo(language_data[self.current_language]['success'],
                              language_data[self.current_language]['color_inverted'])

    def generate_mask(self, color):
        """生成指定颜色的掩膜"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['no_image_loaded'])
            return

        # 检查是否为彩色图像
        if len(self.image.shape) != 3 or self.image.shape[2] != 3:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['color_mask_requires_color_image'])
            return

        # 生成掩膜
        if color == 'red':
            # 红色掩膜：提取红色通道并创建二值掩膜
            red_channel = self.image[:, :, 2]
            # 创建掩膜：红色通道值大于绿色通道和蓝色通道值
            mask = np.logical_and(red_channel > self.image[:, :, 1], red_channel > self.image[:, :, 0])
            # 转换为uint8类型（0和255）
            self.current_mask = (mask * 255).astype(np.uint8)
        elif color == 'green':
            # 绿色通道掩膜
            green_channel = self.image[:, :, 1]
            mask = np.logical_and(green_channel > self.image[:, :, 0], green_channel > self.image[:, :, 2])
            self.current_mask = (mask * 255).astype(np.uint8)
        elif color == 'blue':
            # 蓝色通道掩膜
            blue_channel = self.image[:, :, 0]
            mask = np.logical_and(blue_channel > self.image[:, :, 1], blue_channel > self.image[:, :, 2])
            self.current_mask = (mask * 255).astype(np.uint8)
        else:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['unsupported_color'])
            return

        # 显示掩膜
        self.show_mask_window(color)

    def show_mask_window(self, color):
     """显示掩码窗口并提供保存选项"""
     mask_window = tk.Toplevel(self.master)
     mask_window.title(language_data[self.current_language][f'{color}_mask'])
    
    # 设置固定的画布尺寸
     canvas_width, canvas_height = 300, 300
     canvas = tk.Canvas(mask_window, width=canvas_width, height=canvas_height)
     canvas.pack()

    # 显示掩码图像
     image = Image.fromarray(self.current_mask)
     image_width, image_height = image.size
     scale = min(canvas_width / image_width, canvas_height / image_height)
    
     if scale < 1:
        image = image.resize((int(image_width * scale), int(image_height * scale)), Image.LANCZOS)
     else:
        image = image.resize((int(image_width * scale), int(image_height * scale)), Image.BICUBIC)

     photo = ImageTk.PhotoImage(image)
     x = (canvas_width - image.width) // 2
     y = (canvas_height - image.height) // 2
     canvas.create_image(x, y, anchor=tk.NW, image=photo)
     canvas.image = photo

    # 添加保存按钮
     save_button = tk.Button(mask_window, text=language_data[self.current_language]['save_mask'],
                           command=lambda: self.save_mask(self.current_mask, color))
     save_button.pack(pady=10)

    def save_mask(self, mask, color):
        """保存掩膜图像"""
        save_path = filedialog.asksaveasfilename(
            defaultextension=config.DEFAULT_SAVE_FORMAT,
            filetypes=[("PNG files", "*.png"), ("JPEG files", "*.jpg;*.jpeg")]
        )
        
        if not save_path:
            return

        try:
            image_io.save_image(mask, save_path)
            tk.messagebox.showinfo(language_data[self.current_language]['success'],
                                  language_data[self.current_language]['mask_saved'].format(color, save_path))
            logging.info(f"{color} mask saved to {save_path}")
        except Exception as e:
            tk.messagebox.showerror(language_data[self.current_language]['error'], 
                                   str(e))
            logging.error(f"Failed to save mask: {str(e)}")

    def apply_mask(self, operation):
        """应用掩膜操作"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['no_image_loaded'])
            return

        # 打开文件对话框选择掩膜图像
        mask_path = filedialog.askopenfilename(
            filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.bmp")]
        )
        
        if not mask_path:
            return

        try:
            # 加载掩膜图像
            mask = image_io.load_image(mask_path, as_gray=True)
            
            # 确保掩膜与当前图像尺寸一致
            if mask.shape[:2] != self.image.shape[:2]:
                tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                      language_data[self.current_language]['mask_size_mismatch'])
                return

            # 应用掩膜操作
            if operation == 'and':
                # 与运算（遮罩）
                if len(self.image.shape) == 3:
                    # 彩色图像需要将单通道掩膜扩展为三通道
                    result = cv2.bitwise_and(self.image, self.image, mask=mask)
                else:
                    # 灰度图像直接进行与运算
                    result = cv2.bitwise_and(self.image, self.image, mask=mask)
            elif operation == 'or':
                # 或运算（融合）
                if len(self.image.shape) == 3:
                    # 彩色图像需要将单通道掩膜扩展为三通道
                    result = cv2.bitwise_or(self.image, self.image, mask=mask)
                else:
                    # 灰度图像直接进行或运算
                    result = cv2.bitwise_or(self.image, self.image, mask=mask)
            elif operation == 'xor':
                # 异或运算（差异）
                if len(self.image.shape) == 3:
                    # 彩色图像需要将单通道掩膜扩展为三通道
                    result = cv2.bitwise_xor(self.image, self.image, mask=mask)
                else:
                    # 灰度图像直接进行异或运算
                    result = cv2.bitwise_xor(self.image, self.image, mask=mask)
            else:
                tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                      language_data[self.current_language]['unsupported_operation'])
                return

            # 保存原始图像以便重置
            self.original_image = self.image.copy()
            
            # 应用结果
            self.image = result
            self.display_image()
            
            logging.info(f"Mask applied with {operation} operation")
            tk.messagebox.showinfo(language_data[self.current_language]['success'],
                                  language_data[self.current_language]['mask_applied'].format(operation))
            
        except Exception as e:
            tk.messagebox.showerror(language_data[self.current_language]['error'], 
                                   str(e))
            logging.error(f"Failed to apply mask: {str(e)}")

    def moving_difference(self):
        """移动差分功能"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['no_image_loaded'])
            return

        # 检查是否为灰度图像
        if len(self.image.shape) != 2:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['moving_difference_requires_grayscale'])
            return

        # 保存原始图像以便恢复
        self.original_image = self.image.copy()

        # 创建移动差分窗口
        difference_window = tk.Toplevel(self.master)
        difference_window.title(language_data[self.current_language]['moving_difference'])

        # 创建偏移调节拖动条
        shift_scale = tk.Scale(difference_window, from_=-3, to=3, orient=tk.HORIZONTAL,
                               label=language_data[self.current_language]['shift'],
                               resolution=1, length=300,
                               command=self.update_shift)
        shift_scale.set(self.shift_value)
        shift_scale.pack(padx=10, pady=10)

        # 创建应用按钮
        apply_button = tk.Button(difference_window, text=language_data[self.current_language]['apply'],
                                 command=self.apply_shift)
        apply_button.pack(pady=5)

        # 创建重置按钮
        reset_button = tk.Button(difference_window, text=language_data[self.current_language]['reset'],
                                 command=self.reset_shift)
        reset_button.pack(pady=5)

        # 初始更新显示
        self.update_shift(self.shift_value)

    def update_shift(self, value):
        """更新偏移值并显示预览效果"""
        self.shift_value = int(value)

        # 应用移动差分
        shifted_image = np.roll(self.original_image, self.shift_value, axis=1)
        difference_image = np.abs(self.original_image - shifted_image).astype(np.uint8)

        self.image = difference_image
        self.display_image()

    def apply_shift(self):
        """应用当前偏移值处理到原图"""
        self.original_image = None  # 清除备份
        logging.info(f"移动差分处理已应用，偏移值: {self.shift_value}")
        tk.messagebox.showinfo(language_data[self.current_language]['success'],
                               language_data[self.current_language]['shift_applied'].format(self.shift_value))

    def reset_shift(self):
        """重置移动差分处理"""
        if self.original_image is not None:
            self.image = self.original_image.copy()
            self.display_image()

    def global_threshold_processing(self):
        """全局阈值处理"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['no_image_loaded'])
            return

        # 检查是否为灰度图像
        if len(self.image.shape) != 2:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['threshold_requires_grayscale'])
            return

        # 保存原始图像以便恢复
        self.original_image = self.image.copy()

        # 创建阈值处理窗口
        threshold_window = tk.Toplevel(self.master)
        threshold_window.title(language_data[self.current_language]['global_threshold'])

        # 创建阈值调节拖动条
        threshold_scale = tk.Scale(threshold_window, from_=0, to=255, orient=tk.HORIZONTAL,
                                   label=language_data[self.current_language]['threshold'],
                                   resolution=1, length=300,
                                   command=self.update_threshold)
        threshold_scale.set(self.threshold)
        threshold_scale.pack(padx=10, pady=10)

        # 创建应用按钮
        apply_button = tk.Button(threshold_window, text=language_data[self.current_language]['apply'],
                                 command=self.apply_threshold)
        apply_button.pack(pady=5)

        # 创建重置按钮
        reset_button = tk.Button(threshold_window, text=language_data[self.current_language]['reset'],
                                 command=self.reset_threshold)
        reset_button.pack(pady=5)

        # 初始更新显示
        self.update_threshold(self.threshold)

    def update_threshold(self, value):
        """更新阈值并显示预览效果"""
        self.threshold = int(value)

        # 应用阈值处理
        thresholded_image = np.zeros_like(self.original_image)
        thresholded_image[self.original_image > self.threshold] = 255

        self.image = thresholded_image
        self.display_image()

    def apply_threshold(self):
        """应用当前阈值处理到原图"""
        self.original_image = None  # 清除备份
        logging.info(f"全局阈值处理已应用，阈值: {self.threshold}")
        tk.messagebox.showinfo(language_data[self.current_language]['success'],
                               language_data[self.current_language]['threshold_applied'].format(self.threshold))

    def reset_threshold(self):
        """重置阈值处理"""
        if self.original_image is not None:
            self.image = self.original_image.copy()
            self.display_image()

    def change_language(self):
        """切换语言"""
        # 把language.json文件中的current_language的值改为当前的self.current_language
        self.current_language = self.language_var.get()  # 获取所选择的语言
        utils.write_language_data(language_data, "current_language", self.current_language)
        logging.info(f"当前语言已切换为{self.current_language}。")
        confirm = messagebox.askyesno(language_data[self.current_language]['confirm_restart'],
                                      language_data[self.current_language]['restart_warning'])
        if confirm:
            self.master.destroy()
            subprocess.Popen([sys.executable] + sys.argv)

    # 其余代码保持不变
    def merge_channels(self):
        """合并多个单通道图像为一个多通道图像"""
        # 打开文件对话框,让用户选择多个图像文件
        file_paths = filedialog.askopenfilenames()
        # 如果用户没有选择文件,直接返回
        if not file_paths:
            return

        # 如果只选择了一个文件,显示错误信息并返回
        if len(file_paths) == 1:
            tk.messagebox.showerror(language_data[self.current_language]['error'],
                                    language_data[self.current_language]['single_file_error'])
            return

        try:
            self.image = image_channels.merge_image_channels(file_paths)
        except ValueError as e:
            tk.messagebox.showerror(language_data[self.current_language]['error'], str(e))
            return

        # 显示当前图像
        self.display_image()

    def split_image_channels(self):
        """分割当前图像的通道,并在新窗口中显示每个通道"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['no_image_loaded'])
            return

        if len(self.image.shape) == 2:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['single_channel_error'])
            return

        try:
            channels = image_channels.split_image_channels(self.image)
        except ValueError as e:
            tk.messagebox.showinfo(language_data[self.current_language]['error'], str(e))
            return

        for i, channel in enumerate(channels):
            window = tk.Toplevel(self.master)
            window.title(language_data[self.current_language]['channel_title'].format(i))
            canvas = tk.Canvas(window, width=300, height=300)
            canvas.pack()

            # 定义内部函数用于保存单个通道
            def save_channel(channel, index):
                save_path = filedialog.asksaveasfilename(defaultextension=config.DEFAULT_SAVE_FORMAT)
                if not save_path:
                    return
                image_io.save_image(channel, save_path)
                tk.messagebox.showinfo(language_data[self.current_language]['success'],
                                       language_data[self.current_language]['channel_saved'].format(index, save_path))

            save_button = tk.Button(window, text=language_data[self.current_language]['save_channel'],
                                    command=lambda channel=channel: save_channel(channel, i))
            save_button.pack()

            window.update()

            # 显示子通道图像
            image = Image.fromarray(channel)  # 将通道数据转换为PIL图像对象
            canvas_width = canvas.winfo_width()  # 获取画布的宽度
            canvas_height = canvas.winfo_height()  # 获取画布的高度
            image_width, image_height = image.size  # 获取图像的宽度和高度
            scale = min(canvas_width / image_width, canvas_height / image_height)  # 计算图像的缩放比例
            if scale < 1:  # 如果图像过大,缩小图像
                new_width = int(image_width * scale)
                new_height = int(image_height * scale)
                image = image.resize((new_width, new_height), Image.LANCZOS)  # 使用Lanczos滤波器进行缩小
            else:  # 如果图像过小,放大图像
                new_width = int(image_width * scale)
                new_height = int(image_height * scale)
                image = image.resize((new_width, new_height), Image.BICUBIC)  # 使用双三次滤波器进行放大

            photo = ImageTk.PhotoImage(image)  # 将PIL图像对象转换为PhotoImage对象
            x = (canvas_width - new_width) // 2  # 计算图像在画布上的水平居中位置
            y = (canvas_height - new_height) // 2  # 计算图像在画布上的垂直居中位置
            canvas.create_image(x, y, anchor=tk.NW, image=photo)  # 在画布上显示图像
            canvas.image = photo  # 将PhotoImage对象保存到画布中,防止被垃圾回收

            # 在子图上添加清晰的标题
            title = f"Channel {i}"
            canvas.create_text(canvas_width // 2, 15, text=title, font=("Arial", 15), fill="black")

        logging.info("图像分割操作成功。")  # 记录成功日志

    def show_image_details(self):
        """显示当前图像的详细信息"""
        if self.image is None:  # 如果当前没有图像,显示相应消息并返回
            messagebox.showinfo(language_data[self.current_language]['error'],
                                language_data[self.current_language]['no_image_loaded'])
            logging.info("没有载入任何图像,无法显示图像细节。")  # 记录日志信息
            return

        # 从路径中提取文件名
        filename = os.path.basename(self.image_path)

        # 计算其他基本信息
        total_pixels = self.image.size  # 获取图像的总像素数
        shape = self.image.shape  # 获取图像的形状(高度,宽度,通道数)
        channels = shape[2] if len(shape) == 3 else 1  # 获取图像的通道数，注意不是维度，而是通道数
        dtype = self.image.dtype  # 获取图像像素的数据类型

        # 构建信息字符串,包括文件名
        details = language_data[self.current_language]['info_str'].format(filename, total_pixels, shape, channels, dtype)

        # 显示信息
        messagebox.showinfo("INFO", details)
        logging.info("已显示图像细节。")  # 记录成功日志

    def on_mouse_down(self, event):
        """处理鼠标左键按下事件"""
        if self.current_rect and not self.is_drawing:
            # 如果存在矩形框且不是在拖动状态,删除矩形框并重置状态
            self.canvas.delete(self.current_rect)
            self.current_rect = None
        else:
            # 否则,开始绘制新的矩形框
            self.rect_start_x = event.x
            self.rect_start_y = event.y
            self.is_drawing = True

    def on_mouse_move(self, event):
        """处理鼠标左键移动事件"""
        if self.is_drawing:
            if self.current_rect:
                self.canvas.delete(self.current_rect)
            self.current_rect = self.canvas.create_rectangle(self.rect_start_x, self.rect_start_y, event.x, event.y,
                                                             outline="red")

    def on_mouse_up(self, event):
        """处理鼠标左键释放事件"""
        # 标记矩形的结束点并完成绘制
        self.rect_end_x, self.rect_end_y = event.x, event.y
        self.is_drawing = False
        # 保存裁剪区域的坐标
        self.crop_region = (min(self.rect_start_y, self.rect_end_y), max(self.rect_start_y, self.rect_end_y),
                            min(self.rect_start_x, self.rect_end_x), max(self.rect_start_x, self.rect_end_x))
        logging.info("已绘制裁剪区域。")  # 记录成功日志

    def Open_as_original(self):
        """打开原始图像"""
        logging.info("正在打开原始图像...")
        self.image_path = filedialog.askopenfilename()  # 打开文件对话框,让用户选择图像文件
        if not self.image_path:
            logging.info("没有选择任何图像文件,打开操作已取消。")  # 记录日志信息
            return  # 如果没有选择任何文件,直接返回
        self.image = image_io.load_image(self.image_path)  # 加载图像文件
        self.display_image()  # 显示图像
        logging.info("成功打开原始图像。")  # 记录成功日志

    def Open_as_gray(self):
        """将原始图像转换为灰度图像"""
        self.image_path = filedialog.askopenfilename()  # 打开文件对话框,让用户选择图像文件
        if not self.image_path:
            logging.info("没有选择任何图像文件,打开操作已取消。")  # 记录日志信息
            return  # 如果没有选择任何文件,直接返回
        self.image = image_io.load_image(self.image_path, as_gray=True)  # 加载图像文件并转换为灰度图像
        self.display_image()  # 显示图像
        logging.info("成功打开并转换为灰度图像。")  # 记录成功日志

    def display_image(self):
        """在主画布上显示当前图像"""
        if self.image is None:
            logging.info("当前没有图像可显示。")  # 记录日志信息
            return  # 如果当前没有图像,直接返回

        image = Image.fromarray(self.image)  # 将numpy数组转换为PIL图像对象

        # 计算图像的缩放比例
        canvas_width = self.canvas.winfo_width()  # 获取画布的宽度
        canvas_height = self.canvas.winfo_height()  # 获取画布的高度
        image_width, image_height = image.size  # 获取图像的宽度和高度
        scale = min(canvas_width / image_width, canvas_height / image_height)  # 计算图像的缩放比例

        # 缩放图像
        if scale < 1:
            # 图像过大,缩小图像
            new_width = int(image_width * scale)
            new_height = int(image_height * scale)
            image = image.resize((new_width, new_height), Image.LANCZOS)  # 使用Lanczos滤波器进行缩小
        else:
            # 图像过小,放大图像
            new_width = int(image_width * scale)
            new_height = int(image_height * scale)
            image = image.resize((new_width, new_height), Image.BICUBIC)  # 使用双三次滤波器进行放大

        photo = ImageTk.PhotoImage(image)  # 将PIL图像对象转换为PhotoImage对象
        self.canvas.delete("all")  # 清除画布上的所有内容

        # 计算图像在画布上的居中位置
        x = (canvas_width - new_width) // 2
        y = (canvas_height - new_height) // 2
        self.canvas.create_image(x, y, anchor=tk.NW, image=photo)  # 在画布上显示图像, tk.NW表示图像的左上角对齐画布的左上角
        self.canvas.image = photo  # 将PhotoImage对象保存到画布中,防止被垃圾回收
        logging.info("成功显示图像。")  # 记录成功日志

    def save_image(self):
        """保存当前图像"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['no_image_to_be_saved'])
            logging.error("没有图像可保存,保存操作已取消。")  # 记录错误日志
            return  # 如果当前没有图像,直接返回

        save_path = filedialog.asksaveasfilename(defaultextension=config.DEFAULT_SAVE_FORMAT)  # 打开保存文件对话框
        if not save_path:
            logging.info("没有选择保存路径,保存操作已取消。")  # 记录日志信息
            return  # 如果没有选择保存路径,直接返回

        image_io.save_image(self.image, save_path)  # 将当前图像保存到指定路径
        logging.info(f"图像已成功保存到 {save_path}。")  # 记录成功日志

    def crop_image(self):
        """裁剪当前图像"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['no_image_to_be_cropped'])
            logging.error("没有图像可裁剪,裁剪操作已取消。")  # 记录错误日志
            return  # 如果当前没有图像,直接返回

        # 检查是否有绘制的裁剪区域
        if hasattr(self, 'crop_region') and self.current_rect:
            # 计算实际裁剪区域坐标(考虑图像缩放和偏移)
            image_height, image_width = self.image.shape[:2]  # 获取图像的高度和宽度
            canvas_width = self.canvas.winfo_width()  # 获取画布的宽度
            canvas_height = self.canvas.winfo_height()  # 获取画布的高度
            scale = min(canvas_width / image_width, canvas_height / image_height)  # 计算图像的缩放比例
            offset_x = (canvas_width - image_width * scale) // 2  # 计算图像在画布上的水平偏移量
            offset_y = (canvas_height - image_height * scale) // 2  # 计算图像在画布上的垂直偏移量

            # 计算实际裁剪区域坐标
            real_crop_region = (
                int((self.crop_region[0] - offset_y) / scale),
                int((self.crop_region[1] - offset_y) / scale),
                int((self.crop_region[2] - offset_x) / scale),
                int((self.crop_region[3] - offset_x) / scale)
            )

            cropped_image = image_transform.crop_image(self.image, real_crop_region)  # 裁剪图像
            if cropped_image is not None:
                self.image = cropped_image  # 将裁剪后的图像保存到self.image中
                self.display_image()  # 显示裁剪后的图像
                logging.info("图像裁剪成功。")  # 记录成功日志

                # 清零裁剪框信息
                self.canvas.delete(self.current_rect)  # 删除画布上的裁剪矩形框
                self.current_rect = None  # 将当前裁剪矩形框对象设置为None
                del self.crop_region  # 删除存储裁剪区域坐标的属性
            else:
                tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                       language_data[self.current_language]['crop_failed'])
                logging.error("裁剪操作失败。")  # 记录错误日志
        else:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['no_crop_area'])
            logging.error("没有选择裁剪区域,裁剪操作已取消。")  # 记录错误日志

    def reset_image(self):
        """重置当前图像为原始状态"""
        if not self.image_path:  # 如果没有图像路径,显示错误消息并返回
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['no_reset_image'])
            logging.error("没有图像可重置,重置操作已取消。")  # 记录错误日志
            return
        self.image = image_io.load_image(self.image_path)  # 重新加载图像
        self.display_image()  # 显示图像
        logging.info("图像已重置为原始状态。")  # 记录成功日志

    def adjust_brightness(self):
        """调节图像亮度"""
        if self.image is None:
            tk.messagebox.showinfo(language_data[self.current_language]['error'],
                                   language_data[self.current_language]['no_image_to_be_adjusted'])
            logging.error("没有图像可调节亮度,亮度调节操作已取消。")
            return

        # 保存原始图像以便重置
        self.original_image = self.image.copy()

        # 创建亮度调节窗口
        brightness_window = tk.Toplevel(self.master)
        brightness_window.title(language_data[self.current_language]['brightness_adjust'])
        brightness_window.geometry("300x150")
        brightness_window.resizable(False, False)

        # 创建亮度标签
        brightness_label = tk.Label(brightness_window, text=language_data[self.current_language]['brightness_value'] + " 100%")
        brightness_label.pack(pady=10)

        # 创建亮度滑块 (0-200，默认100)
        brightness_scale = tk.Scale(brightness_window, from_=0, to=200, orient=tk.HORIZONTAL, length=250, resolution=1)
        brightness_scale.set(100)  # 默认值100%
        brightness_scale.pack(pady=10)

        # 应用亮度变化的函数
        def apply_brightness(event=None):
            brightness_percent = brightness_scale.get()
            brightness_factor = brightness_percent / 100.0

            # 应用亮度调整
            if brightness_factor == 1.0:  # 100%亮度，直接使用原始图像
                self.image = self.original_image.copy()
            else:
                # 调整亮度：使用乘法调整亮度，保持颜色平衡
                if len(self.original_image.shape) == 3:  # 彩色图像
                    # 分离RGB通道
                    r, g, b = cv2.split(self.original_image)
                    # 分别调整每个通道的亮度
                    r = np.clip(r * brightness_factor, 0, 255).astype(np.uint8)
                    g = np.clip(g * brightness_factor, 0, 255).astype(np.uint8)
                    b = np.clip(b * brightness_factor, 0, 255).astype(np.uint8)
                    # 合并调整后的通道
                    self.image = cv2.merge([r, g, b])
                else:  # 灰度图像
                    self.image = np.clip(self.original_image * brightness_factor, 0, 255).astype(np.uint8)

            # 更新亮度标签和显示图像
            brightness_label.config(text=language_data[self.current_language]['brightness_value'] + f" {brightness_percent}%")
            self.display_image()

        # 绑定滑块事件
        brightness_scale.bind("<Motion>", apply_brightness)
        brightness_scale.bind("<ButtonRelease-1>", apply_brightness)

        # 添加按钮框
        button_frame = tk.Frame(brightness_window)
        button_frame.pack(pady=10)

        # 应用按钮
        apply_button = tk.Button(button_frame, text=language_data[self.current_language]['apply'],
                                 command=lambda: brightness_window.destroy())
        apply_button.pack(side=tk.LEFT, padx=10)

        # 取消按钮
        cancel_button = tk.Button(button_frame, text="取消",
                                  command=lambda: cancel_brightness())
        cancel_button.pack(side=tk.LEFT, padx=10)

        # 取消亮度调整
        def cancel_brightness():
            self.image = self.original_image.copy()
            self.display_image()
            brightness_window.destroy()

        # 窗口关闭时恢复原始图像
        brightness_window.protocol("WM_DELETE_WINDOW", cancel_brightness)

 # 新增：在language_data中添加必要的键值对
if 'edge' not in language_data['zh']:
    language_data['zh']['edge'] = '边缘'
    language_data['zh']['moving_difference'] = '移动差分'
    language_data['zh']['shift'] = '偏移值'
    language_data['zh']['shift_applied'] = '移动差分处理已应用，偏移值: {0}'
    language_data['zh']['moving_difference_requires_grayscale'] = '移动差分处理只能在灰度图像上进行'

if 'edge' not in language_data['en']:
    language_data['en']['edge'] = 'Edge'
    language_data['en']['moving_difference'] = 'Moving Difference'
    language_data['en']['shift'] = 'Shift Value'
    language_data['en']['shift_applied'] = 'Moving difference processing applied with shift value: {0}'
    language_data['en']['moving_difference_requires_grayscale'] = 'Moving difference processing requires a grayscale image'
 
if 'mask' not in language_data['zh']:
    language_data['zh']['mask'] = '掩模'
    language_data['zh']['generate_mask'] = '生成掩模'
    language_data['zh']['apply_mask'] = '应用掩模'
    language_data['zh']['red_mask'] = '红色掩模'
    language_data['zh']['green_mask'] = '绿色通道'
    language_data['zh']['blue_mask'] = '蓝色通道'
    language_data['zh']['save_mask'] = '保存掩模'
    language_data['zh']['mask_saved'] = '已保存{0}掩模到{1}'
    language_data['zh']['and_operation'] = '与运算'
    language_data['zh']['not_operation'] = '非运算'
    language_data['zh']['mask_applied'] = '已应用{0}掩模操作'
    language_data['zh']['color_mask_requires_color_image'] = '颜色掩模需要彩色图像'
    language_data['zh']['unsupported_color'] = '不支持的颜色'
    language_data['zh']['mask_size_mismatch'] = '掩模尺寸与当前图像不匹配'
    language_data['zh']['unsupported_operation'] = '不支持的操作'

if 'mask' not in language_data['en']:
    language_data['en']['mask'] = 'Mask'
    language_data['en']['generate_mask'] = 'Generate Mask'
    language_data['en']['apply_mask'] = 'Apply Mask'
    language_data['en']['red_mask'] = 'Red Mask'
    language_data['en']['green_mask'] = 'Green Mask'
    language_data['en']['blue_mask'] = 'Blue Mask'
    language_data['en']['save_mask'] = 'Save Mask'
    language_data['en']['mask_saved'] = '{0} mask saved to {1}'
    language_data['en']['and_operation'] = 'AND Operation'
    language_data['en']['not_operation'] = 'NOT Operation'
    language_data['en']['mask_applied'] = '{0} mask operation applied'
    language_data['en']['color_mask_requires_color_image'] = 'Color mask requires a color image'
    language_data['en']['unsupported_color'] = 'Unsupported color'
    language_data['en']['mask_size_mismatch'] = 'Mask size does not match current image'
    language_data['en']['unsupported_operation'] = 'Unsupported operation'

if 'create_mask' not in language_data['zh']:
    language_data['zh']['create_mask'] = '创建掩膜'
    language_data['zh']['bitwise_operations'] = '位运算'
    language_data['zh']['or_operation'] = '或运算（融合）'
    language_data['zh']['xor_operation'] = '异或运算（差异）'

if 'create_mask' not in language_data['en']:
    language_data['en']['create_mask'] = 'Create Mask'
    language_data['en']['bitwise_operations'] = 'Bitwise Operations'
    language_data['en']['or_operation'] = 'OR Operation (Fusion)'
    language_data['en']['xor_operation'] = 'XOR Operation (Difference)'
    
if 'invert_color' not in language_data['zh']:
    language_data['zh']['invert_color'] = '反色'
    language_data['zh']['not_operation_invert'] = '非运算（反转）'
    language_data['zh']['color_inverted'] = '图像已反色处理'

if 'invert_color' not in language_data['en']:
    language_data['en']['invert_color'] = 'Invert Color'
    language_data['en']['not_operation_invert'] = 'NOT Operation (Invert)'
    language_data['en']['color_inverted'] = 'Image color has been inverted'


# 创建主窗口和应用程序实例
root = tk.Tk()
app = ImageProcessor(root)
root.mainloop()